/*
 * @Author: 黄威
 * @Date: 2023-03-09 15:04:26
 * @LastEditors: 黄威
 * @LastEditTime: 2024-09-29 10:08:02
 * @Description: 标绘图层和标号列表
 */
import { Ref, forwardRef, useCallback, useImperativeHandle, useMemo, useRef, useState } from 'react';
import { Empty, Modal, Tree, TreeDataNode, TreeProps } from 'antd';
import styles from './index.module.scss';
import useTreeDrag from './useTreeDrag';
import useTreeEdit, { type ActionType } from './useTreeEdit';
import { useMemoizedFn } from 'ahooks';

interface ActionTreeProps extends TreeProps {
  // 标题点击
  onTitleClick?: (node: any) => void;

  // title的属性
  onTitleDoubleClick?: (node: any, action: ActionType) => void;

  // 节点是否为有效的拖动
  dragChecker?: (evt: any) => boolean;

  // tree后面的 action Button 渲染
  actionRender?: (node: any, action: ActionType) => JSX.Element;

  // 编辑后回调
  onUpdate?: () => void;

  // [key: string]: any;
}

function ActionTree(
  props: ActionTreeProps,
  ref: Ref<{
    forceUpdate: () => void;
    getNodeById: (id: string | number) => any;
    setCheck: (id: string | number, checked: boolean) => void;
    isChecked: (id: string | number) => boolean;
  }>,
) {
  const { onTitleClick, onTitleDoubleClick, dragChecker, actionRender, onUpdate, treeData, ..._props } = props;

  const treeRef = useRef<any>();

  // 配置读取，一些功能可能要使用
  const { fieldNames, draggable } = _props;
  const { title = 'title', key = 'key', children = 'children' } = fieldNames ?? {};

  // 查找遍历相关
  const loop = useCallback(
    (
      data: TreeDataNode[],
      innerkey: React.Key,
      callback: (node: TreeDataNode, i: number, data: TreeDataNode[]) => void,
    ) => {
      for (let i = 0; i < data.length; i++) {
        if (data[i][key] === innerkey) {
          return callback(data[i], i, data);
        }
        if (data[i][children]) {
          loop(data[i][children]!, innerkey, callback);
        }
      }
    },
    [key, children],
  );

  // 检测是否有重名
  const checkSameName = useCallback(
    (node: any, dataList: any[]) => {
      return new Promise((resolve, reject) => {
        const flag = !!dataList.find((d) => d[title] === node[title] && d[key] !== node[key]);
        if (flag) {
          Modal.confirm({
            title: '操作确认',
            content: `该目录已经存在 ${node[title]}，是否确认操作`,
            onOk() {
              resolve(true);
            },
            onCancel() {
              reject();
            },
          });
        } else {
          resolve(true);
        }
      });
    },
    [title, key],
  );

  // 强制刷新相关
  const [refreshKey, setRefreshKey] = useState({});
  const treeDataMemo = useMemo(
    () => (refreshKey && Array.isArray(treeData) ? [...treeData] : undefined),
    [treeData, refreshKey],
  );
  const forceUpdate = useMemoizedFn(() => {
    setRefreshKey({});
    onUpdate && onUpdate();
  });

  // 节点拖动
  const { onDrop } = useTreeDrag({ loop, checkSameName, draggable, fieldNames, treeData, dragChecker, forceUpdate });
  // 节点编辑
  const { titleWrapper } = useTreeEdit({ loop, checkSameName, fieldNames, treeData, forceUpdate });
  // 目录编辑（避免创建内联函数，减少dom更新频率）
  const titleRender = useCallback(
    (node: any) =>
      titleWrapper(node, (action) => (
        <div className="flex items-center leading-2em">
          <span
            className="flex-1 pl-0.5em ellipsis"
            title={node[title]}
            onClick={() => onTitleClick && onTitleClick(node)}
            onDoubleClick={() => onTitleDoubleClick && onTitleDoubleClick(node, action)}
          >
            {node[title]}
          </span>
          {actionRender ? actionRender(node, action) : <></>}
        </div>
      )),
    [titleWrapper, title, actionRender, onTitleClick, onTitleDoubleClick],
  );

  // 支持ref方法
  useImperativeHandle(
    ref,
    () => {
      const handler = {
        forceUpdate,
        getNodeById(id: string | number) {
          const entities = treeRef.current?.state.keyEntities ?? {};
          return entities[id];
        },
        setCheck(node: any, checked: boolean) {
          if (!treeRef.current) return;

          const nodeKey = node[key];
          node = { ...node, key: nodeKey };
          treeRef.current?.onNodeCheck({}, node, checked);

          // 删除的时候，节点应该肯定是存在的
          if (!handler.getNodeById(nodeKey) && checked) {
            const state = { ...treeRef.current.state };
            state.checkedKeys = [...state.checkedKeys, nodeKey];
            treeRef.current.setState(state);
          }
        },
        isChecked(id: string | number) {
          if (!treeRef.current) return;
          return treeRef.current.state.checkedKeys.includes(id);
        },
      };

      return handler;
    },
    [forceUpdate, key],
  );

  return (
    <>
      <Tree
        x-if={treeDataMemo && treeDataMemo.length}
        className={styles['action-tree']}
        ref={treeRef}
        {..._props}
        treeData={treeDataMemo}
        onDrop={onDrop}
        blockNode
        titleRender={titleRender}
      />
      <Empty x-else />
    </>
  );
}

export default forwardRef(ActionTree);
